#ifndef MODELSTRUCTS_H_
#define MODELSTRUCTS_H_

//#include "precom.h"
#include "fmtxlib.h"
#include <vector>
#include <list>
#include <cmath>

inline float maxf(float x, float y) { return (x>y)?x:y; }
inline float minf(float x, float y) { return (x<y)?x:y; }

struct Vertex
{
	float m_position[3];

	Vertex() {}
	Vertex(const fmath::vector3& a_vec)
	{
		m_position[0] = a_vec.x;
		m_position[1] = a_vec.y;
		m_position[2] = a_vec.z;
	}
};

struct Normal
{
	unsigned long m_vertexNum;
	float m_normal[3];

	Normal() {}
	Normal(const float* a_n, unsigned long a_ind)
	{
		m_normal[0] = a_n[0]; 
		m_normal[1] = a_n[1];
		m_normal[2] = a_n[2];
		m_vertexNum = a_ind;
	}
	Normal(const fmath::vector3& a_n, unsigned long a_ind)
	{ 
		m_normal[0] = a_n.x; 
		m_normal[1] = a_n.y;
		m_normal[2] = a_n.z;
		m_vertexNum = a_ind;
	}
};

struct Triangle
{
	unsigned long m_normals[3];
};

struct Box
{
	fmath::vector3 m_min;
	fmath::vector3 m_max;

	static const Box ZERO;

	Box(float minX = 0.f, float minY = 0.f, float minZ = 0.f, 
		float maxX = 0.f, float maxY = 0.f, float maxZ = 0.f)
	{
		m_min.x = minX; m_min.y = minY;
		m_min.z = minZ; m_max.x = maxX;
		m_max.y = maxY; m_max.z = maxZ;
	}
	Box(const fmath::vector3 &a_min, const fmath::vector3 &a_max)
		:m_min(a_min), m_max(a_max) {}

	bool operator==(const Box &a_box) const 
	{ return (m_min == a_box.m_min) && (m_max == a_box.m_max); }
	bool operator!=(const Box &a_box) const
	{ return (m_min != a_box.m_min) || (m_max != a_box.m_max); }

	Box operator+() const 
		{ return *this; }
	Box operator-() const 
		{ return Box(-m_min, -m_max); }
	Box operator+(const fmath::vector3& a_v) const
		{ return Box( m_min + a_v, m_max + a_v ); }
	Box operator-(const fmath::vector3& a_v) const
		{ return Box( m_min - a_v, m_max - a_v ); }
	Box operator * (float f) const 
		{ return Box(m_min*f, m_max*f); }
	Box operator * (const fmath::vector3 &a_v) const 
	{ return Box( m_min.x*a_v.x, m_min.y*a_v.y, m_min.z*a_v.z, m_max.x*a_v.x, m_max.y*a_v.y, m_max.z*a_v.z); }
	Box& operator += (const fmath::vector3 &a_v) 
		{ m_min += a_v; m_max += a_v; return *this; }
	Box& operator -= (const fmath::vector3 &a_v) 
		{ m_min -= a_v; m_max -= a_v; return *this; }
	Box& operator *= (float f) 
		{ m_min *= f; m_max *= f; return *this; }
	Box& operator *= (const fmath::vector3 &a_s) 
		{ m_min.x *= a_s.x; m_min.y *= a_s.y; m_min.z *= a_s.z; m_max.x *= a_s.x; m_max.y *= a_s.y; m_max.z *= a_s.z; return *this; }


	void EnlargeBBox(float*);
	void EnlargeBBox(const Box&);
	void Set(float a_x, float a_y, float a_z, 
		float a_sizeX, float a_sizeY, float a_sizeZ);
	void Extend(float v)
		{ m_min.x -= v; m_min.y -= v; m_min.z -= v;
		  m_max.x += v; m_max.y += v; m_max.z += v;}
	void GetSize(fmath::vector3& o_size) 
	{	o_size.x = m_max.x - m_min.x; 
		o_size.y = m_max.y - m_min.y; 
		o_size.z = m_max.z - m_min.z;  }

	void CalcCenter(fmath::vector3& o_size) 
	{	o_size.x = (m_max.x + m_min.x)/2.f; 
		o_size.y = (m_max.y + m_min.y)/2.f; 
		o_size.z = (m_max.z + m_min.z)/2.f;  }

	void Clear()
	{	*this = ZERO; }
	inline float GetMaxSize()
	{
		return maxf(maxf(m_max.x - m_min.x, m_max.y - m_min.y), m_max.z - m_min.z);
	}
	inline float GetMinSize()
	{
		return minf(minf(m_max.x - m_min.x, m_max.y - m_min.y), m_max.z - m_min.z);
	}
};

struct Mesh
{
	std::string				m_name;
	std::vector<Vertex>		m_vertices;
	std::vector<Normal>		m_normals;
	std::vector<Triangle>	m_triangles;
	float					m_color[3];
	Box						m_bbox;

	void GetTriangleVertexes(unsigned long a_triangleNum, unsigned long* o_vertTab) const;
};
#endif //MODELSTRUCTS_H_